home *** CD-ROM | disk | FTP | other *** search
- /**** ewindow.c ****/
- /* By Paul Field
- * See !ReadMe file for distribution/modification restrictions
- */
-
- #include "ewindow.h"
-
- #include <assert.h>
- #include <limits.h>
- #include <stdio.h>
- #include "cache.h"
- #include "edraw.h"
- #include "esprite.h"
- #include "alarm.h"
- #include "bbc.h"
- #include "colourtran.h"
- #include "flex.h"
- #include "sprite.h"
- #include "template.h"
- #include "werr.h"
- #include "wimpt.h"
- #include "win.h"
-
- /* Patch to make heap calls look like flex calls */
- #include "heap.h"
- #define flex_alloc(a,s) ((*(a) = heap_alloc(s)) != NULL)
- #define flex_free(a) do{ heap_free(*a); *a = NULL;}while(FALSE)
-
-
- /**** #defines for werr() ****/
- #define ERR_NonFatal 0
- #define ERR_Fatal 1
-
-
- /* I may alter all the BOOLs in the structure to be bits in an integer -
- * this will save 20bytes/window at the expense of slightly more processing time.
- */
-
- struct ewindow_str
- { wimp_w handle;
- const char *title;
- ewindow_closefn closefn;
- void *closehandle;
- wimp_box workarea;
- edraw_info *info;
- unsigned int timeout; /* Time spent drawing each section */
- unsigned int drawgap; /* Gap between drawing sections */
- void *cache; /* Address of drawing cache (may == structure) */
- BOOL sprite; /* If TRUE window redraws with a sprite if possible */
- ewindow_spritemode mode; /* Mode of the sprite */
- sprite_area *area; /* Sprite area containing window sprite */
- /* - NULL if no sprite */
- BOOL drawspritewait;/* TRUE if waiting for cache before draw starts */
- BOOL firsttime; /* TRUE if 'drawing' but none drawn yet */
- BOOL drawing; /* True if the sprite is still being drawn */
- unsigned int currenty; /* Current Y Position of drawing */
- BOOL redrawwait; /* TRUE if window is waiting to be redrawn */
- BOOL freesprite; /* TRUE -> sprite memory freed on close */
- };
-
- /*************************************************************************************
- Conditions that should be true given that certain flags or tests are true.
- Alarms and processes only concern the window that the test applies to.
-
- Given the window is drawing into a sprite :
- Conditions that must be true :
- sprite
- area != NULL
-
- ----------------+-------+-------------------+
- |'draw' | 'draw' process |
- Test/Flag | alarm | pending | running |
- ----------------+-------+---------+---------+
- drawspritewait | N | Y | N |
- !drawspritewait | ? | N | N |
- drawing | Y | N | Y |
- !drawing | N | N | N |
- ----------------+-------+---------+---------+
-
- NOTES:
- drawspritewait and drawing should not be TRUE together
- redrawwait should always be FALSE
-
- **************************************************************************************
-
- Given the window is not drawing into a sprite :
- Conditions that must be true :
- area == NULL
-
- ---------------+-------+-------------------+
- | redraw| 'redraw' process |
- Test/Flag | alarm | pending | running |
- ---------------+-------+---------+---------+
- redrawwait | N | Y | N |
- !redrawwait | N | N | N* | * - Except during the actual redraw code
- ---------------+-------+---------+---------+
- NOTES:
- drawspritewait and drawing should always be FALSE
-
- **************************************************************************************/
-
- /* Tentative process definition (I may make 'process' a data type and provide a
- * module to handle processes).
- * start - Called to start the process
- * finish - Called to finish a running process
- * setup - Starts the process waiting for the resource
- * removeall - Removes all copies of process from the waiting queue and terminates
- * process if it is currently running
- *
- * May also have process types :
- * one - only one of the process may be queuing at a time.
- * many - several of the process may be queueing.
- */
-
-
-
- static void ewindow_redrawsprite(ewindow ew);
- static void ewindow_redrawloopsprite(ewindow ew, wimp_redrawstr *rect, BOOL morerects);
- static void ewindow_makesprite(ewindow ew);
- static void ewindow_drawsprite(ewindow ew);
- static void ewindow_removesprite(ewindow ew);
- static void ewindow_spritedrawstart(void *d, void *handle);
- static void ewindow_spritedrawcontinue(int time, void *handle);
- static void ewindow_spritedrawfinish(ewindow ew);
- static void ewindow_spritedrawsetup(ewindow ew);
- static void ewindow_spritedrawremoveall(ewindow ew);
- static void ewindow_euclidupdate(ewindow ew);
- static void ewindow_redrawloopeuclid(ewindow ew, wimp_redrawstr *rect, BOOL morerects,
- BOOL update);
- static void ewindow_redrawloopeuclidcacheok(ewindow ew, wimp_redrawstr *rect,
- BOOL morerects);
- static void ewindow_delayedredrawstart(void *d, void *handle);
- static void ewindow_delayedredrawsetup(ewindow ew);
- static void ewindow_delayedredrawremoveall(ewindow ew);
- static void ewindow_redrawerror(ewindow ew);
- static void ewindow_redraw(ewindow ew);
- static void ewindow_redrawloop(ewindow ew, wimp_redrawstr *rect, BOOL more, BOOL update);
- static void ewindow_handler(wimp_eventstr *e, void *info);
- static BOOL ewindow_unknownhandler(wimp_eventstr *e, void *info);
-
-
- /******* Code for sprite-drawn windows *******/
-
- static void ewindow_redrawsprite(ewindow ew)
- { wimp_redrawstr r;
- BOOL more;
-
- assert(ew->area);
- r.w = ew->handle;
- r.box = ew->workarea;
- wimpt_noerr(wimp_update_wind(&r, &more));
- ewindow_redrawloopsprite(ew, &r, more);
- }
-
-
- static void ewindow_redrawloopsprite(ewindow ew, wimp_redrawstr *rect, BOOL morerects)
- { sprite_id id;
- os_error *e = NULL;
- sprite_factors factors;
- sprite_pixtrans pixtrans[256];
- int mode;
-
- id.tag = sprite_id_addr;
- id.s.addr = (char *)ew->area + ew->area->sproff;
- wimp_readpixtrans(ew->area, &id, &factors, pixtrans);
- mode = ((sprite_header *)id.s.addr)->mode;
- if (bbc_modevar(mode, bbc_Log2BPP) == 3)
- { e = colourtran_select_table(mode, 0, -1, (wimp_paletteword *) -1, pixtrans);
- }
- while(morerects && !e)
- { e = sprite_put_scaled(ew->area, &id, 0,
- rect->box.x0 - rect->scx + ew->workarea.x0,
- rect->box.y1 - rect->scy + ew->workarea.y0,
- &factors, pixtrans);
- if (!e)
- { e = wimp_get_rectangle(rect, &morerects);
- }
- }
- wimpt_noerr(e); /* Leave wimpt_noerr until here as it could move the sprite */
- }
-
-
- static void ewindow_makesprite(ewindow ew)
- { if (ew->sprite)
- { int size;
- int width, height;
- int mode;
- int dx,dy,bpc,bpp;
-
- if (ew->area)
- { flex_free((flex_ptr)&ew->area);
- }
- mode = (ew->mode == ewindow_smdynamic ? wimpt_mode() : ew->mode);
- dx = 1<<bbc_modevar(mode, bbc_XEigFactor);
- dy = 1<<bbc_modevar(mode, bbc_YEigFactor);
- bpc = 1<<bbc_modevar(mode, bbc_Log2BPC);
- bpp = 1<<bbc_modevar(mode, bbc_Log2BPP);
- width = (ew->workarea.x1-ew->workarea.x0 + dx-1)/dx;
- height = (ew->workarea.y1-ew->workarea.y0 + dy-1)/dy;
- size = ((width*bpc+7)/8+3)/4; /* Size of horizontal line in words */
- size = height*size*4 + sizeof(sprite_header)+sizeof(sprite_area);
- if (flex_alloc((flex_ptr)&ew->area, size))
- { sprite_area_initialise(ew->area, size);
- if (!wimpt_complain(sprite_create(ew->area, "s", FALSE, width, height, mode)))
- { ew->info->timeout = ew->timeout;
- ewindow_drawsprite(ew);
- }
- else
- { ewindow_removesprite(ew);
- }
- }
- }
- }
-
- static void ewindow_drawsprite(ewindow ew)
- { if (ew->area)
- { ewindow_spritedrawfinish(ew);
- ewindow_spritedrawsetup(ew);
- }
- }
-
-
- static void ewindow_removesprite(ewindow ew)
- { if (ew->area)
- { BOOL update;
-
- flex_free((flex_ptr)&ew->area);
- update = ew->drawing;
- ewindow_spritedrawremoveall(ew);
- ew->info->timeout = 0;
- if (update || (ew->mode != ewindow_smdynamic && ew->mode != wimpt_mode()))
- { ewindow_update(ew);
- }
- }
- }
-
-
- /******* sprite draw process *******/
-
-
- static void ewindow_spritedrawstart(void *d, void *handle)
- { ewindow ew = handle;
-
- d = d;
- assert(ew->area);
- ew->drawspritewait = FALSE;
- ew->drawing = TRUE;
- ew->firsttime = TRUE;
- ew->currenty = ew->workarea.y1-ew->workarea.y0;
- ew->info->xoffset = -ew->workarea.x0;
- ew->info->yoffset = -ew->workarea.y0;
- ewindow_spritedrawcontinue(0,handle);
- }
-
-
- static void ewindow_spritedrawcontinue(int time, void *handle)
- { ewindow ew = handle;
-
- time=time;
- if (wimpt_complain(esprite_draw(&ew->area, ew->area->sproff, ew->info)))
- { ewindow_removesprite(ew);
- ewindow_euclidupdate(ew);
- }
- else
- { wimp_redrawstr r;
- BOOL more;
- int nexty;
-
- nexty = (ew->info->timedout ? ew->info->infoblock->nexty : -4);
- r.w = ew->handle;
- r.box.x0 = ew->workarea.x0;
- r.box.x1 = ew->workarea.x1;
- r.box.y0 = nexty + ew->workarea.y0+4;
- r.box.y1 = ew->currenty + ew->workarea.y0+4;
- wimpt_noerr(wimp_update_wind(&r, &more));
- ewindow_redrawloopsprite(ew, &r, more);
-
- if (ew->info->timedout)
- { ew->currenty = nexty;
- alarm_set(alarm_timenow()+ew->drawgap, ewindow_spritedrawcontinue, ew);
- }
- else
- { ewindow_spritedrawfinish(ew);
- }
- }
- }
-
-
- static void ewindow_spritedrawfinish(ewindow ew)
- { if (ew->drawing)
- { cache_finished(ew->cache);
- if (ew->info->timedout)
- { edraw_stop(ew->info);
- }
- alarm_removeall(ew);
- ew->drawing = FALSE;
- }
- }
-
-
- static void ewindow_spritedrawsetup(ewindow ew)
- { if (!ew->drawspritewait)
- { ew->drawspritewait = TRUE;
- if (!cache_callwhenfree(ew->cache, ewindow_spritedrawstart, ew))
- { ewindow_redrawerror(ew);
- ew->drawspritewait = FALSE;
- }
- }
- }
-
-
- static void ewindow_spritedrawremoveall(ewindow ew)
- { if (ew->drawspritewait)
- { ew->drawspritewait = FALSE;
- cache_removeallprocesses(ew->cache, ew); /* A bit OTT, but OK for now */
- }
- ewindow_spritedrawfinish(ew);
- }
-
-
- /******* Code for euclid-drawn windows *******/
-
- static void ewindow_euclidupdate(ewindow ew)
- { wimp_redrawstr r;
- BOOL more;
-
- r.w = ew->handle;
- r.box = ew->workarea;
- wimpt_noerr(wimp_update_wind(&r, &more));
- ewindow_redrawloop(ew, &r, more, TRUE);
- }
-
- static void ewindow_redrawloopeuclid(ewindow ew, wimp_redrawstr *rect, BOOL morerects,
- BOOL update)
- { if (ew->redrawwait || cache_inuse(ew->cache))
- { /* No cache to draw the picture with - blank it and redraw later */
- wimp_setcolour(0);
- while(morerects)
- { if (!update)
- { bbc_clg();
- }
- wimpt_noerr(wimp_get_rectangle(rect, &morerects));
- }
- ewindow_delayedredrawsetup(ew);
- }
- else
- { ewindow_redrawloopeuclidcacheok(ew, rect, morerects);
- }
- }
-
-
- static void ewindow_redrawloopeuclidcacheok(ewindow ew, wimp_redrawstr *rect,
- BOOL morerects)
- { if (ew->info->structure->cache)
- { *((unsigned int *)ew->info->structure->cache + 1) = 0;
- }
- while(morerects)
- { ew->info->xoffset = rect->box.x0-rect->scx;
- ew->info->yoffset = rect->box.y1-rect->scy;
- wimpt_complain(edraw_split(ew->info));
- wimpt_noerr(wimp_get_rectangle(rect, &morerects));
- }
- }
-
-
- /***** delayed redraw process *****/
-
- static void ewindow_delayedredrawstart(void *d, void *handle)
- { ewindow ew = handle;
- wimp_redrawstr r;
- BOOL more;
-
- d=d;
- assert(!ew->area);
- ew->redrawwait = FALSE;
- r.w = ew->handle;
- r.box = ew->workarea;
- wimpt_noerr(wimp_update_wind(&r, &more));
- ewindow_redrawloopeuclidcacheok(ew, &r, more);
- cache_finished(ew->cache);
- }
-
-
- static void ewindow_delayedredrawsetup(ewindow ew)
- { if (!ew->redrawwait)
- { ew->redrawwait = TRUE;
- if (!cache_callwhenfree(ew->cache, ewindow_delayedredrawstart, ew))
- { ewindow_redrawerror(ew);
- ew->redrawwait = FALSE;
- }
- }
- }
-
- static void ewindow_delayedredrawremoveall(ewindow ew)
- { if (ew->redrawwait)
- { ew->redrawwait = FALSE;
- cache_removeallprocesses(ew->cache, ew); /* A bit OTT, but OK for now */
- }
- }
-
-
- /********* Code for redrawing a window ********/
-
- static void ewindow_redrawerror(ewindow ew)
- { char error[256];
- sprintf(error, "Unable to redraw window '%s'.",ew->title);
- werr(ERR_NonFatal, error);
- }
-
- static void ewindow_redraw(ewindow ew)
- { wimp_redrawstr rect;
- BOOL morerects;
-
- rect.w = ew->handle;
- wimpt_noerr(wimp_redraw_wind(&rect, &morerects));
- ewindow_redrawloop(ew, &rect, morerects, FALSE);
- }
-
- static void ewindow_redrawloop(ewindow ew, wimp_redrawstr *rect, BOOL morerects,
- BOOL update)
- { if (ew->area)
- { ewindow_redrawloopsprite(ew, rect, morerects);
- }
- else
- { ewindow_redrawloopeuclid(ew, rect, morerects, update);
- }
- }
-
-
- /******** Handle wimp events ********/
-
- static void ewindow_handler(wimp_eventstr *e, void *info)
- { ewindow ew = info;
-
- switch(e->e)
- { case wimp_EREDRAW: ewindow_redraw((ewindow)info); break;
- case wimp_EOPEN: wimpt_noerr(wimp_open_wind(&e->data.o)); break;
- case wimp_ECLOSE: ew->closefn(ew, ew->closehandle); break;
- }
- }
-
-
- #define ewindow_spriteaddr(ew) ((sprite_header *)(char *)(ew)->area + (ew)->area->sproff)
-
- static BOOL ewindow_unknownhandler(wimp_eventstr *e, void *info)
- { ewindow ew = info;
-
- switch(e->e)
- { case wimp_ESEND:
- case wimp_ESENDWANTACK:
- switch(e->data.msg.hdr.action)
- { case wimp_MMODECHANGE:
- wimpt_checkmode();
- if ((ew->area && ew->mode == ewindow_smdynamic &&
- ewindow_spriteaddr(ew)->mode != wimpt_mode()) ||
- (ew->sprite && !ew->area))
- { ewindow_makesprite(ew);
- }
- break;
- case wimp_PALETTECHANGE:
- euclid_invalidatepalettecache();
- if (ew->area &&
- (ew->info->style & (emainstyle_raytrace*edrawstyle_mainstyle)))
- { ewindow_redrawsprite(ew);
- }
- else
- { ewindow_update(ew);
- }
- break;
- }
- }
- return(FALSE); /* Allow other windows a chance to see events */
- }
-
-
-
- /******** Create and manipulate windows ********/
-
- ewindow ewindow_create(const char *title, euclid_drawstyle style,
- euclid_header *structure, const char *camera,
- ewindow_closefn cfn, void *handle)
- { ewindow ew;
- edraw_info *info;
- wimp_wind *window;
-
- if ((window = template_syshandle("ewindow")) == NULL)
- { werr(ERR_NonFatal, "Template 'ewindow' not found");
- return(NULL);
- }
- window->titleflags |= wimp_INDIRECT;
- window->title.indirecttext.buffer = (char *)title;
- if ((ew = malloc(sizeof(*ew))) == NULL)
- { return(NULL);
- }
- if ((info = malloc(sizeof(*info))) == NULL)
- { free(ew);
- return(NULL);
- }
- if (wimpt_complain(wimp_create_wind(window, &ew->handle)) != 0)
- { free(info);
- free(ew);
- return(NULL);
- }
- edraw_initialise(info);
- info->structure = structure;
- info->camera = camera;
- info->style = style & 0x7ff;
- info->timeout = 0;
-
- ew->info = info;
- ew->title = title;
- ew->closefn = cfn;
- ew->closehandle = handle;
- ew->workarea = window->ex;
- ew->cache = cache_address(structure);
- ew->timeout = 0;
- ew->sprite = FALSE;
- ew->area = NULL;
- ew->drawspritewait = FALSE;
- ew->drawing = FALSE;
- ew->redrawwait = FALSE;
- ew->freesprite = TRUE;
- win_register_event_handler(ew->handle, ewindow_handler, ew);
- win_add_unknown_event_processor(ewindow_unknownhandler, ew);
- wimpt_checkmode();
- return(ew);
- }
-
-
- void ewindow_usesprite(ewindow ew, BOOL sprite, ewindow_spritemode mode)
- { ew->sprite = sprite;
-
- if (sprite)
- { if (mode == ewindow_smcurrent)
- { mode = wimpt_mode();
- }
- if (!ew->area || mode != ew->mode)
- { if (!ew->area)
- { ewindow_delayedredrawremoveall(ew);
- }
- ew->mode = mode;
- ewindow_makesprite(ew);
- }
- }
- else
- { if (ew->area)
- { ewindow_removesprite(ew);
- }
- }
- }
-
- void ewindow_timing(ewindow ew, char timeout, unsigned int drawgap)
- { ew->timeout = timeout;
- ew->drawgap = drawgap;
- if (ew->area)
- { ew->info->timeout = timeout;
- }
- }
-
- void ewindow_setstyle(ewindow ew, euclid_drawstyle style)
- { style &= 0x7ff;
-
- if (ew->info->style != style)
- { ew->info->style = style;
- ewindow_update(ew);
- }
- }
-
-
- void ewindow_open(ewindow ew)
- { wimp_wstate wstate;
-
- wimpt_noerr(wimp_get_wind_state(ew->handle, &wstate));
- wstate.o.behind = -1;
- wimpt_noerr(wimp_open_wind(&wstate.o));
- if (!ew->area)
- { ewindow_makesprite(ew);
- }
- }
-
- void ewindow_closeoptions(ewindow ew, BOOL freesprite)
- { ew->freesprite = freesprite;
- }
-
- BOOL ewindow_hassprite(ewindow ew)
- { return(ew->area != NULL);
- }
-
- BOOL ewindow_sprite(ewindow ew, sprite_area ***area, int *offset)
- { *area = &ew->area;
- *offset = ew->area->sproff;
- return(ew->area != NULL);
- }
-
- BOOL ewindow_updatecomplete(ewindow ew)
- { return(!ew->drawing && !ew->drawspritewait && !ew->redrawwait);
- }
-
-
- void ewindow_update(ewindow ew)
- { if (ew->area)
- { ewindow_drawsprite(ew);
- }
- else
- { ewindow_euclidupdate(ew);
- }
- }
-
-
- void ewindow_close(ewindow ew)
- { wimpt_noerr(wimp_close_wind(ew->handle));
- if (ew->area && ew->freesprite)
- { ewindow_removesprite(ew);
- }
- if (!ew->area)
- { ewindow_delayedredrawremoveall(ew);
- }
- }
-
- void ewindow_destroy(ewindow ew)
- { win_register_event_handler(ew->handle, NULL, NULL);
- win_remove_unknown_event_processor(ewindow_unknownhandler, ew);
- wimpt_noerr(wimp_delete_wind(ew->handle));
- ewindow_removesprite(ew);
- ewindow_delayedredrawremoveall(ew);
- free(ew);
- }
-
- wimp_w ewindow_handle(ewindow ew)
- { return(ew->handle);
- }
-